package com.parlons;

import android.content.Context;
import android.database.Cursor;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.CursorAdapter;
import android.widget.SimpleCursorAdapter;

import com.parlons.activities.FriendsFragment;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManagerListener;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Registration;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 * Created by wangyifan on 15/12/22.
 */
public class SmackServices {

    private static XMPPConnection connection;
    public static Handler UIHandler = new Handler(Looper.getMainLooper());
    private static Context applicationContext;
    private static String userName;

    public static XMPPConnection getConnection() {
        return connection;
    }

    public static String getUserName() {
        return userName;
    }

    public static void setUserNull() {
        userName = null;
    }

    public static String extend(String username) {
        if (username.contains("@"))
            return username.split("@")[0] + "@120.26.218.166";
        else
            return username + "@120.26.218.166";
    }

    public static String getUserNameFromJID(String JID) {
        if (JID.contains("@")) {
            JID = JID.split("@")[0];
        }
        return JID;
    }

    public static boolean conServer(final Context context) {


        if (applicationContext != null)
            applicationContext = context;
        if (connection != null && connection.isConnected()) {
            System.out.println("connected , remove chat and new");
            Collection<ChatManagerListener> c = connection.getChatManager().getChatListeners();
            for (ChatManagerListener chat : c) {
                connection.getChatManager().removeChatListener(chat);
            }
            TaxiChatManagerListener chatManagerListener = new TaxiChatManagerListener(context);
            connection.getChatManager().addChatListener(chatManagerListener);
            return true;
        }
        Roster.setDefaultSubscriptionMode(Roster.SubscriptionMode.manual);
        final ConnectionConfiguration config = new ConnectionConfiguration(
                "120.26.218.166");
        config.setSASLAuthenticationEnabled(false);
        try {
            /** if the connection is initialized, then don't do it again */
            if (connection == null)
                connection = new XMPPConnection(config);
            connection.getRoster().setSubscriptionMode(Roster.SubscriptionMode.manual);
            /** Add a packet listener to listen the subscription messages */
            connection.addPacketListener(new PacketListener() {

                @Override
                public void processPacket(Packet packet) {
                    Presence presence = (Presence) packet; //the presence received
                    System.out.print("******* received a packet:");
                    System.out.println(presence);
                    System.out.print("******* from:");
                    System.out.println(presence.getFrom());
                    System.out.print("******* to:");
                    System.out.println(presence.getTo());

                    if (presence.getType() == Presence.Type.subscribe) {
                        System.out.println("******* subscribe");
                        try {
                            Roster roster = connection.getRoster();

                            if (!roster.contains(presence.getFrom())) // the sender is not in the roster, to agree, send subscribed.
                            {
                                // if agree
                                //TODO
                                Presence presence_request = new Presence(Presence.Type.subscribed);
                                presence_request.setTo(extend(presence.getFrom())); // send back a presence
                                presence_request.setType(Presence.Type.subscribed);
                                presence_request.setFrom(extend(connection.getUser()));
                                // getUser method has a /Smack
                                connection.sendPacket(presence_request);
                                System.out.println("send subscribed from:" + presence_request.getFrom() + "to:" + presence_request.getTo());
                                addUser(roster, getUserNameFromJID(presence.getFrom()), null);
                            } else { //the sender is in the roster, it's a agree reply with subscribe
                                // automatically agree
                                Presence presence_request = new Presence(Presence.Type.subscribed);
                                presence_request.setTo(extend(presence.getFrom())); // send back a presence
                                presence_request.setType(Presence.Type.subscribed);
                                presence_request.setFrom(extend(connection.getUser()));
                                connection.sendPacket(presence_request);
                                System.out.println("send subscribed automatically from:" + presence_request.getFrom() + "to:" + presence_request.getTo());
                            }
                        } catch (Exception e) {
                            System.out.println(e);
                        }
                        return;
                    }
                    if (presence.getType() == Presence.Type.subscribed) {
                        System.out.println("******* subscribed");
                        try {

                        } catch (Exception e) {
                            System.out.println(e);
                            e.printStackTrace();
                        }
                        return;
                    }
                    if (presence.getType() == Presence.Type.unsubscribe) // reject the apply
                    {
                        try {

                            String friendUsername = SmackServices.getUserNameFromJID(presence.getFrom());
                            Roster roster = SmackServices.getConnection().getRoster();
                            if (roster.contains(friendUsername)) {
                                DatabaseServices DBService = DatabaseServices.getInstance(context);
                                RosterEntry friend = roster.getEntry(friendUsername);
                                if (!DBService.friendExists(SmackServices.getUserName(), friendUsername)) {
                                    DBService.deleteFriend(SmackServices.getUserName(), friendUsername);
                                    System.out.println("delete new friends");
                                }
                                DBService.close();
                            }
                        } catch (Exception e) {
                            System.out.println(e);
                        }
                        return;
                    }
                    if (presence.getType() == Presence.Type.unsubscribed) // apply is rejected
                    {
                        try {
                            //TODO: do something
                        } catch (Exception e) {
                            System.out.println(e);
                        }
                        return;
                    }
                    System.out.println("******* none???");
                }
            }, new PacketTypeFilter(Presence.class));

            /** connect */
            connection.connect();
            TaxiChatManagerListener chatManagerListener = new TaxiChatManagerListener(context);
            connection.getChatManager().addChatListener(chatManagerListener);
            return true;
        } catch (XMPPException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 注册
     *
     * @param account
     * @param password
     * @return 1、success 0、no result 2、account exists 3、fail
     */
    public static int register(String account, String password) {
        if (connection == null)
            return -1;
        Registration reg = new Registration();
        reg.setType(IQ.Type.SET);
        reg.setTo(connection.getServiceName());
        reg.setUsername(account);// 注意这里creteAccount注册时，参数是username，不是jid，是“@”前面的部分。
        reg.setPassword(password);
        reg.addAttribute("android", "createUser_android");
        PacketFilter filter = new AndFilter(new PacketIDFilter(
                reg.getPacketID()), new PacketTypeFilter(IQ.class));
        PacketCollector collector = connection
                .createPacketCollector(filter);
        connection.sendPacket(reg);
        IQ result = (IQ) collector.nextResult(SmackConfiguration
                .getPacketReplyTimeout());
        // Stop queuing results
        collector.cancel();// 停止请求results（是否成功的结果）
        if (result == null) {
            Log.e("RegisterActivity", "No response from server.");
            return 0;
        } else if (result.getType() == IQ.Type.RESULT) {
            return 1;
        } else { // if (result.getType() == IQ.Type.ERROR)
            if (result.getError().toString().equalsIgnoreCase("conflict(409)")) {
                Log.e("RegisterActivity", "IQ.Type.ERROR: "
                        + result.getError().toString());
                return 2;
            } else {
                Log.e("RegisertActivity", "IQ.Type.ERROR: "
                        + result.getError().toString());
                return 3;
            }
        }
    }

    /**
     * login
     *
     * @param a account
     * @param p password
     * @return
     */

    public static boolean login(String a, String p) {
        System.out.println("login begins");
        try {
            if (connection == null)
                return false;
            /** 登录 */
            while (!connection.isConnected()) {
                SmackServices.conServer(applicationContext);
                Thread.sleep(1000, 0);
            }

            System.out.println("login");
            connection.login(a, p);
            userName = getUserNameFromJID(connection.getUser());
            System.out.println("同步问题,username:" + userName);
//            isAuthenticated = true;
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * the function has a problem because of Smack problem
     *
     * @param connection
     * @return
     */
    public static boolean logOut(XMPPConnection connection) {
        try {
            connection.getAccountManager().deleteAccount();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * get list of firneds
     *
     * @param roster
     * @return
     */
    public static List<RosterEntry> getAllEntries(Roster roster) {
        List<RosterEntry> Entrieslist = new ArrayList<RosterEntry>();
        Collection<RosterEntry> rosterEntry = roster.getEntries();
        Iterator<RosterEntry> i = rosterEntry.iterator();
        while (i.hasNext()) {
            Entrieslist.add(i.next());
        }
        return Entrieslist;
    }


    /**
     * add friend
     *
     * @param roster
     * @param userName
     * @param name
     * @return
     */
    public static boolean addUser(Roster roster, String userName, String name) { //userName is not extended
        if ((userName != getUserNameFromJID(connection.getUser())) && (!roster.contains(extend(userName)))) // The friend is not user self and doesn't exist in the roster
        {
            try {
                Presence subscribe = new Presence(Presence.Type.subscribe); // ask for subscription
                subscribe.setTo(extend(userName));
                subscribe.setFrom(extend(connection.getUser()));
                subscribe.setType(Presence.Type.subscribe);
                connection.sendPacket(subscribe);  /** The result of getUser is JID */
                roster.createEntry(extend(userName), null, null); /** send the request, add ****JID**** to roster */

                List<RosterEntry> friendList = SmackServices.getAllEntries(roster);

                DatabaseServices DBService = DatabaseServices.getInstance(applicationContext);
                boolean exist = DBService.friendExists(SmackServices.getUserName(), userName);
                System.out.println("exist:" + exist);
                if (!exist) {
                    DBService.addFriend(SmackServices.getUserName(), userName, name);
                }
                DBService.close();
                UIHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        while (FriendsFragment.simpleCursorAdapter == null) {
                            System.out.println("1 null");
                            try {
                                DatabaseServices DBService = DatabaseServices.getInstance(applicationContext);
                                Cursor cursor = DBService.getFriendsCursor(SmackServices.getUserName());
                                FriendsFragment.simpleCursorAdapter = new SimpleCursorAdapter(applicationContext, R.layout.friends_item, cursor, new String[]{"friend_username"}, new int[]{R.id.friends_list_username}, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

                            } catch (Exception e) {
                                e.printStackTrace();
                                return;
                            }
                        }

                        DatabaseServices DBService = DatabaseServices.getInstance(applicationContext);
                        Cursor cursor = DBService.getFriendsCursor(SmackServices.getUserName());
                        if (cursor == null)
                            System.out.println("cursor null");
                        FriendsFragment.simpleCursorAdapter.changeCursor(cursor);
                    }
                });


                return true;

            } catch (Exception e) {
                System.err.println(e);
                return false;
            }
        } else
            return false;
    }

    /**
     * delete friend
     *
     * @param roster
     * @param userName
     * @return
     */
    public static boolean removeUser(Roster roster, String userName) {
        try {
            if (userName.contains("@")) {
                userName = userName.split("@")[0];
            }

            RosterEntry entry = roster.getEntry(userName);
            System.out.println("删除好友：" + userName);
            System.out.println("User." + roster.getEntry(userName) == null);
            roster.removeEntry(entry);

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static Map<String, Chat> chatManage = new HashMap<String, Chat>();

    /**
     * get chat window
     *
     * @param friend   friend
     * @param listener chat listener
     * @return
     */
    public static Chat getFriendChat(String friend, MessageListener listener) {
        if (getConnection() == null)
            return null;
        for (String fristr : chatManage.keySet()) {
            if (fristr.equals(friend)) {
                return chatManage.get(fristr);
            }
        }
        Chat chat = getConnection().getChatManager().createChat(friend + "@" +
                getConnection().getServiceName(), listener);
        chatManage.put(friend, chat);
        return chat;
    }

    public static void sendToFriend(String friend, String mess) {
        Chat chat = getFriendChat(friend, null);
        try {
            chat.sendMessage(mess);
        } catch (XMPPException e) {
            e.printStackTrace();
        }

    }


}
